package com.wmd.validation.aop;

import com.wmd.core.exceptions.GenericResponse;
import com.wmd.core.exceptions.ValidationException;
import com.wmd.core.util.YKArrayUtils;
import com.wmd.validation.annotation.FileValidation;
import com.wmd.validation.util.LogMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * 类说明
 * 
 * @author yincheng lu
 * @time 2019年1月4日上午11:11:39
 * @Description
 */
@Aspect
@Component
@Order(2)
public class ParamsValidation {
	private static final Log logger = LogFactory.getLog(ParamsValidation.class);

//	@Pointcut("execution(public * *..controller..*.*(..)) && @annotation(com.wmd.validation.annotation.ParamsValidate)") // ||(execution(*
	@Pointcut("@annotation(com.wmd.validation.annotation.ParamsValidate)") // ||(execution(*
	public static void paramsValidate() {
	}

	@Autowired
	MessageSource messageSource;

	@Before("paramsValidate()")
	public void doBeforeInServiceLayer(JoinPoint joinPoint) {

	}

	@After("paramsValidate()")
	public void doAfterInServiceLayer(JoinPoint joinPoint) {

	}
	@Value(value = "${wmd.BaseEntityPackage:#{null}}")
	private String BaseEntityPackage;

	@Around("paramsValidate()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		if(null==BaseEntityPackage||"".equals(BaseEntityPackage)){
			return pjp.proceed();
		}
		logger.info("start to validation params");
		Map<String, String> resultMap = new HashMap<>();
		Object[] arguments = pjp.getArgs();//实际参数
		//参数放到日志里添加
//		LogManage.tl_msg.get().setArguments(YKArrayUtils.getOtherClassFromArray(arguments,BindingResult.class));
		Method realMethod = LogManage.getProceedJoinPointMethod(pjp);
		Parameter[] parameters = realMethod.getParameters();//方法参数
		// StringBuffer bf = new StringBuffer();
		// 验证参数错误
		List<BindingResult> brs = YKArrayUtils.getClassFromArray(arguments, BindingResult.class);
		if (brs != null && brs.size() > 0) {
			brs.forEach(br -> {
				// BindingResult br = (BindingResult) arguments[i];
				if (br.hasErrors()) {
					br.getFieldErrors().forEach(e -> {
						/*
						 * try { logger.info(Charset.defaultCharset());
						 * logger.info(System.getProperty("file.encoding"));
						 * logger.info(e.getDefaultMessage()+"error:"+new
						 * String(e.getDefaultMessage().getBytes("GBK"),"UTF-8")); } catch
						 * (UnsupportedEncodingException e1) { // TODO Auto-generated catch block
						 * e1.printStackTrace(); }
						 */
						// System.out.println(e.getDefaultMessage());
						resultMap.put(e.getField() + "", messageSource.getMessage(e, LocaleContextHolder.getLocale()));
						// bf.append(e.getField() + ":" + messageSource.getMessage(e,
						// LocaleContextHolder.getLocale())+" ");
					});
					br.getGlobalErrors().forEach(e -> {
						/*
						 * try { logger.info(Charset.defaultCharset());
						 * logger.info(System.getProperty("file.encoding"));
						 * logger.info(e.getDefaultMessage()+"error:"+new
						 * String(e.getDefaultMessage().getBytes("GBK"),"UTF-8")); } catch
						 * (UnsupportedEncodingException e1) { // TODO Auto-generated catch block
						 * e1.printStackTrace(); }
						 */
						// System.out.println(e.getDefaultMessage());
						resultMap.put(e.getObjectName() + "",
								messageSource.getMessage(e, LocaleContextHolder.getLocale()));
						// bf.append(e.getField() + ":" + messageSource.getMessage(e,
						// LocaleContextHolder.getLocale())+" ");
					});
				}
			});
		}
		/*
		 * RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		 * ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		 * HttpServletRequest request = sra.getRequest();
		 */
		Set<String> keys = null;
		MultipartHttpServletRequest multipartRequest = null;
		List<MultipartHttpServletRequest> multipartRequests = YKArrayUtils.getClassFromArray(arguments,
				MultipartHttpServletRequest.class);
		if (multipartRequests != null && multipartRequests.size() > 0) {// 是否文件上传
			// logger.info("*****************is multipartRequest");
			// logger.info(JSON.toJSONString(multipartRequest.getFileMap()));
			logger.info("request is multipart!");
			multipartRequest = multipartRequests.get(0);
			LogManage.tl_msg.get().setInputFileParamMap(multipartRequest.getFileMap());
			// MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)
			// request;
			keys = multipartRequest.getFileMap().keySet();
		} else {

		}
		List<Object> models = YKArrayUtils.getClassFromArrayInPackage(arguments, BaseEntityPackage);//获取实际model参数
		if (models != null && models.size() > 0) {
			for (int m = 0; m < models.size(); m++) {
				Object model = models.get(m);
				// System.out.println(keys);
				for (int i = 0; i < parameters.length; i++) {
					// IntStream.range(0, parameters.length).forEach(i -> {
					Class<?> bean = parameters[i].getType();// 获取参数class
					// logger.info(bean.getName() + "：判断bean");
					if (bean.getName().contains(BaseEntityPackage)) {// 判断是否model中class
						logger.info(bean.getName() + ":入参bean");
						Annotation validate = parameters[i].getAnnotation(Validated.class);// 获取validation注解
						Class<?>[] groups = {};
						if (validate != null) {
							Validated validatedReal = (Validated) validate;
							groups = validatedReal.value();// 获取分组
							// System.out.println(groups[0].getName());
						}
						Field[] fields = parameters[i].getType().getDeclaredFields();
						for (int j = 0; j < fields.length; j++) {
							FileValidation fileValidation = fields[j].getAnnotation(FileValidation.class);//遍历model中含有注解的参数
							if (fileValidation != null) {
								// logger.info("get fileValidation!");
								if (groups != null && groups.length > 0) {//controller中分组为空，默认启用bean中所有分组
									Class<?>[] beanGroups = fileValidation.groups();
									if (beanGroups == null || beanGroups.length == 0) {//bean没有分组，controller中有分组，则分组不匹配
										// logger.info("bean group is null!");
										continue;
									} else {
										if (!YKArrayUtils.intersection(groups, beanGroups)) {//controller中参数与bean中参数分组没有交集
											// logger.info("no intersection!");
											continue;
										}
									}
								}
								// logger.info("in group!");
								if (fileValidation.delayFile()) {//如果是延迟文件，跳过
									continue;
								} else {
									if (fileValidation.fileNotEmpty()) {//如果文件可以为空，跳过
										if (!fileValidation.conditionField().trim().equals("")
												&& fileValidation.conditionFieldValue().length > 0) {//如果文件有条件限制
											try {
												Field field = bean
														.getDeclaredField(fileValidation.conditionField().trim());
												field.setAccessible(true);
												Object o = field.get(model);
												if (!Arrays.asList(fileValidation.conditionFieldValue()).contains(o)) {//根据是否参数符合条件
													continue;
												}
											} catch (NoSuchFieldException | SecurityException | IllegalArgumentException
													| IllegalAccessException e) {
												// TODO Auto-generated catch block
												e.printStackTrace();
											}
										}
										if (keys != null && multipartRequest != null) {//判断request是否有文件参数
											if (keys.contains(fields[j].getName() + LogMessage.FILE_SUFFIX)) {//判断request中是否有该文件
												MultipartFile mf = multipartRequest
														.getFile(fields[j].getName() + LogMessage.FILE_SUFFIX);
												if (mf.getSize() > fileValidation.size()) {//判断文件大小限制
													resultMap.put(fields[j].getName(), "文件名:" + fields[j].getName()
															+ "大小超过限制：<" + fileValidation.size() / 1024 + "Mb");
													continue;
												}
												if (!Arrays.asList(fileValidation.type()).contains(//判断文件类型限制
														mf.getOriginalFilename().split("\\.")[1].toLowerCase())) {
													StringBuffer bf = new StringBuffer();
													for (int f = 0; f < fileValidation.type().length; f++) {
														bf.append(fileValidation.type()[f] + ",");
													}
													bf.deleteCharAt(bf.length() - 1);
													resultMap.put(fields[j].getName(), "文件名:" + fields[j].getName()
															+ "类型限制：[" + bf.toString() + "]");
												}
												continue;
											} else if (keys.contains(fields[j].getName())) {//判断文件名是否缺少后缀
												resultMap.put(fields[j].getName(), "文件名:" + fields[j].getName()
														+ "需要后缀:" + LogMessage.FILE_SUFFIX);
											} else {
												resultMap.put(fields[j].getName(), "缺少文件:" + fields[j].getName());
											}
										} else {
											resultMap.put(fields[j].getName(), "缺少文件:" + fields[j].getName());
										}
									} else {
										continue;
									}
								}
							}
							;
						}
						;
					}
				}
				;
			}
		}
		if (resultMap.size() > 0) {
//			return HttpMessage.create(HttpCode.PARAM_ERROR, "参数错误", resultMap);
			throw  new ValidationException(400, resultMap,"参数错误");
		} else {
			Object result = pjp.proceed();// result的值就是被拦截方法的返回值
			// logger.info(result.getClass());
			return result;
		}

	}
}
